package com.yc.sole.erp.repository;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yc.sole.erp.dto.MoldDto;
import com.yc.sole.erp.dto.ProductDto;
import com.yc.sole.erp.entity.Product;
import com.yc.sole.erp.entity.StockLog;
import com.yc.sole.erp.enums.StockOperationType;
import com.yc.sole.erp.exception.ErpResultEnum;
import com.yc.sole.erp.mapper.ProductMapper;
import com.yc.sole.erp.request.ProductQueryReq;
import com.yc.sole.framework.exception.BaseException;
import com.yc.sole.framework.mybatis.page.Paging;
import com.yc.sole.framework.mybatis.util.PageUtil;
import com.yc.sole.framework.result.BaseResultEnum;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 服务接口实现
 *
 * @author yizuomin
 * @date 2023-12-15
 **/
@Slf4j
@Service
@RequiredArgsConstructor
public class ProductRepository extends ServiceImpl<ProductMapper, Product> {

    private final StockLogRepository stockLogRepository;

    /**
     * 新增
     *
     * @param productDto
     */
    @Transactional(rollbackFor = Exception.class)
    public Long saveProduct(ProductDto productDto) {
        Product entity = new Product();
        BeanUtil.copyProperties(productDto, entity);
        this.save(entity);
        return entity.getId();
    }

    /**
     * 通过Id修改
     *
     * @param productDto
     * @return RestResult
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateProductById(ProductDto productDto) {
        Product entity = new Product();
        BeanUtil.copyProperties(productDto, entity);
        this.updateById(entity);
    }

    /**
     * 通过id删除
     *
     * @param ids
     * @return RestResult
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteProductByIds(Collection<Long> ids) {
        this.removeBatchByIds(ids);
    }

    /**
     * 根据id获取
     *
     * @param ids
     * @return RestResult
     */
    public List<ProductDto> selectProductByIds(Set<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return BeanUtil.copyToList(this.listByIds(ids), ProductDto.class);
    }

    /**
     * 根据id获取
     *
     * @param id
     * @return RestResult
     */
    public ProductDto selectProductById(Long id) {
        return BeanUtil.copyProperties(this.getById(id), ProductDto.class);
    }

    /**
     * 根据详情获取
     *
     * @param moldId
     * @return RestResult
     */
    public ProductDto selectByIdDetail(Long moldId, String color, String material, String size, String length) {
        LambdaQueryWrapper<Product> wrapper = Wrappers.<Product>lambdaQuery()
                .eq(Product::getMoldId, moldId)
                .eq(Product::getColor, color)
                .eq(Product::getMaterial, material)
                .eq(Product::getSize, size)
                .eq(Product::getLength, length);
        return BeanUtil.copyProperties(this.getOne(wrapper), ProductDto.class);
    }

    /**
     * 保存并返回
     *
     * @param moldDto
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public ProductDto saveAndReturn(MoldDto moldDto, String color, String material, String size, String length) {
        Product product = new Product();
        product.setMoldId(moldDto.getId());
        product.setMoldName(moldDto.getMoldName());
        product.setProductName(CharSequenceUtil.join("*", moldDto.getMoldName(), color, material, size));
        product.setUnit(moldDto.getUnit());
        product.setCategoryId(moldDto.getCategoryId());
        product.setCategoryName(moldDto.getCategoryName());
        product.setColor(color);
        product.setMaterial(material);
        product.setSize(size);
        product.setLength(length);
        product.setWeight(moldDto.getWeight());
        product.setStock(0);
        boolean save = this.save(product);
        if (!save) {
            throw new BaseException(BaseResultEnum.FAIL);
        }
        return BeanUtil.copyProperties(product, ProductDto.class);
    }

    /**
     * 分页查询
     *
     * @param page
     * @return RestResult
     */
    public Paging<ProductDto> selectProductPage(Paging page, ProductQueryReq productPageReq) {
        LambdaQueryWrapper<Product> queryWrapper = Wrappers.<Product>lambdaQuery()
                .like(CharSequenceUtil.isNotBlank(productPageReq.getProductName()), Product::getProductName, productPageReq.getProductName())
                .orderByDesc(Product::getStock)
                .orderByAsc(Product::getId);
        return PageUtil.pageCopy(this.page(PageUtil.toMybatisPage(page), queryWrapper), ProductDto.class);
    }

    /**
     * 根据名称查询
     *
     * @param productName
     * @return
     */
    public List<ProductDto> selectProductByName(String productName) {
        LambdaQueryWrapper<Product> wrapper = Wrappers.<Product>lambdaQuery()
                .like(CharSequenceUtil.isNotBlank(productName), Product::getProductName, productName)
                .orderByAsc(Product::getProductName);
        Page<Product> productPage = new Page<>(1, 10);
        return BeanUtil.copyToList(this.page(productPage, wrapper).getRecords(), ProductDto.class);
    }

    /**
     * 变更产品库存
     *
     * @param productId
     * @param updateStock 修改的库存数量 正数为加 负数为减
     * @param remark      变动备注
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateStock(Long productId, Integer updateStock, String remark) {
        if (updateStock == null || updateStock == 0) {
            return;
        }
        // 查询
        ProductDto productDto = this.selectProductById(productId);
        if (Objects.isNull(productDto)) {
            throw new BaseException(ErpResultEnum.PRODUCT_NOT_FOUND);
        }
        // 新的剩余库存
        int newStock = productDto.getStock() + updateStock;
        // 库存不足
        if (newStock < 0) {
            throw new BaseException(ErpResultEnum.STOCK_NOT_ENOUGH, productDto.getProductName());
        }
        LambdaUpdateWrapper<Product> wrapper = Wrappers.<Product>lambdaUpdate()
                .eq(Product::getId, productId)
                .eq(Product::getStock, productDto.getStock())
                .set(Product::getStock, newStock);
        boolean update = this.update(wrapper);
        if (!update) {
            throw new BaseException(BaseResultEnum.FAIL);
        }
        StockLog stockLog = new StockLog();
        stockLog.setProductId(productDto.getId());
        stockLog.setProductName(productDto.getProductName());
        if (updateStock > 0) {
            stockLog.setType(StockOperationType.ADD);
        } else {
            stockLog.setType(StockOperationType.DEDUCT);
        }
        stockLog.setQuantity(Math.abs(updateStock));
        stockLog.setBeforeStock(productDto.getStock());
        stockLog.setAfterStock(newStock);
        stockLog.setUnit(productDto.getUnit());
        stockLog.setRemark(remark);
        stockLogRepository.save(stockLog);
    }

    static Integer stock = 100;

    public static void main(String[] args) {
        testStock(10);
        testStock(10);
        testStock(-50);
    }

    public static void testStock(Integer updateStock) {
        stock = stock - updateStock;
        System.out.println(stock);
    }
}
